﻿#include"XQHttpReplyAccount.h"
#include"XQHttpHeadRequest.h"
#include"XQLog.hpp"
#include"XQMySql.hpp"
#include"XQAccountData.h"
#include"XQAlgorithm.h"
#include"XQMail.h"
#include<QTcpSocket>
#include<QEventLoop>
#include<QRegularExpression>
#include"XQFuncEvent.h"
#include"XQFuncEventFilter.hpp"
#include"XSymbolOverload.h"
#include<QTimer>
#include<QSet>
#include<QBuffer>
using namespace HttpAccount;
XQHttpReplyAccount::XQHttpReplyAccount(QObject* parent)
	:XQHttpReplyObject(parent)
{
	installEventFilter(new XQFuncEventFilter(this));
	m_timer = new QTimer(this);
	m_timer->setInterval(1_mins);
	m_timer->callOnTimeout(this,&XQHttpReplyAccount::timedTask);
	//m_timer->start();
}

int XQHttpReplyAccount::emailBindAccountCount() const
{
	return m_emailBindAccountCount;
}

QSize XQHttpReplyAccount::portraitMaxSize() const
{
	return m_portraitMaxSize;
}

bool XQHttpReplyAccount::isLogin(QIODevice* socket)
{
	QReadLocker lock(&m_loginAccountLock);
	return m_loginAccount.contains(socket);
}

QString XQHttpReplyAccount::loginAccount(QIODevice* socket)
{
	QReadLocker lock(&m_loginAccountLock);
	return m_loginAccount.value(socket);
}

QStringList XQHttpReplyAccount::loginAccounts()
{
	QReadLocker lock(&m_loginAccountLock);
	return m_loginAccount.values();
}


void XQHttpReplyAccount::setUserMysql(XQMySql* mysql)
{
	m_userMysql = mysql;
	if(m_userMysql)
		connect(m_userMysql, &XQMySql::connectionSucceed, this, &XQHttpReplyAccount::userMysql_init);
}


void XQHttpReplyAccount::setMail(XQMail* mail)
{
	m_mail = mail;
	//绑定发送邮件
	/*if(m_mail)
		connect(this,&XQHttpReplyAccount::SendMail,m_mail,&XQMail::SendMail,Qt::QueuedConnection);*/
}

void XQHttpReplyAccount::setRamClearInterval(int msec)
{
	m_timer->setInterval(msec);
}

void XQHttpReplyAccount::setEmailBindAccountCount(int count)
{
	m_emailBindAccountCount = count;
}

void XQHttpReplyAccount::setPortraitMaxSize(const QSize& size)
{
	m_portraitMaxSize = size;
}

void XQHttpReplyAccount::setPortraitMaxSize(int w, int h)
{
	setPortraitMaxSize(QSize(w,h));
}

void XQHttpReplyAccount::setAccountFormat(const QString& regex)
{
	m_accountFormat = regex;
}

void XQHttpReplyAccount::setPasswordFormat(const QString& regex)
{
	m_passwordFormat = regex;
}

bool XQHttpReplyAccount::isAccountExist_mysql(const QString& account, QSharedPointer<XQMySql> mysql)
{
	if (account.isEmpty())
		return false;
	if (mysql == nullptr)
		mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto num = mysql->SELECT_COUNT(UserTable, "`account`=?", { account });
	if (num>0)
		return true;
	return false;
}

int XQHttpReplyAccount::emailBindAccountCount_mysql(const QString& account, QSharedPointer<XQMySql> mysql)
{
	if (mysql == nullptr)
		mysql = m_userMysql->cloneDatabase_SharedPointer();
	return mysql->SELECT_COUNT(UserTable, "`email`=?", { account });
}

QVariant XQHttpReplyAccount::accountInfo_mysql(const QString& account, const QString& field, QSharedPointer<XQMySql> mysql)
{
	if (mysql == nullptr)
		mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto data = mysql->findData(UserTable, { field }, "`account`=?", { account });
	if (data.isEmpty())
		return QVariant();
	return data.front();
}


XQAccountData XQHttpReplyAccount::accountInfo_mysql(const QString& account, const QStringList& fields, QSharedPointer<XQMySql> mysql)
{
	if (mysql == nullptr)
		mysql = m_userMysql->cloneDatabase_SharedPointer();
	XQAccountData acc;
	mysql->SELECT_Where(UserTable, fields,&acc, "`account`=?", { account });
	return acc;
}
void XQHttpReplyAccount::timedTask()
{
	QWriteLocker lock(&m_verifyLock);
	clearVerify(m_accountVerify);
	clearVerify(m_emailVerify);
	//看看还有没有任务
	if (m_accountVerify.isEmpty() && m_emailVerify.isEmpty())
		m_timer->stop();//暂停定时器
}

void XQHttpReplyAccount::clearVerify(QHash<QString, HttpAccount::Verify*>& hash)
{
	for (auto it = hash.begin(); it != hash.end();)
	{
		auto verify = it.value();
		if (verify==nullptr||!verify->isValid())
		{
			if(verify)
				delete verify;
			it = hash.erase(it);
		}
		else
		{
			it++;
		}
	}
}

void XQHttpReplyAccount::clearVerify(QHash<QString, HttpAccount::Verify*>& hash, const QString& key)
{
	if (!hash.contains(key))
		return;
	if(hash[key])
		delete hash[key];
	hash.remove(key);
}
bool XQHttpReplyAccount::isAccepted(XQHttpHeadObject* head) const
{
	if (head == nullptr || head->header(Head::App) != appName())
		return false;//判断请求头是否是这个app
	if (head->header(Head::Command) != Head::Account)
		return false;
	return true;
}
XQHttpHeadReply XQHttpReplyAccount::reply(QIODevice* socket, XQHttpHeadRequest* header)
{
	if (socket == nullptr || header == nullptr)
		return XQHttpHeadReply();
	//QTcpSocket* Socket = static_cast<QTcpSocket*>(socket);
	auto Command = header->header(Head::Command);
	auto Type= header->header(Head::Type);
	if (Command == Head::Account)
	{
		auto json = QJsonDocument::fromJson(header->content()).object();
		if (Type == Head::Login)
			return Account_Login(socket, json);
		else if (Type == Head::Logout)
			return Account_Logout(socket, json);
		else if (Type == Head::Register)
			return Account_Register(socket, json);
		else if (Type == Head::NewEmailVerify)
			return Account_NewEmailVerify(socket, json);
		else if (Type == Head::BindEmailVerify)
			return Account_BindEmailVerify(socket, json);
		else if (Type == Head::ModifyPassword)
			return Account_ModifyPassword(socket, json);
		else if (Type == Head::ModifyInfo)
			return Account_ModifyInfo(socket, json);
		else if (Type == Head::ModifyEmail)
			return Account_ModifyEmail(socket, json);
		else if (Type == Head::Portrait)
			return Account_portrait(socket, json);
		else if (Type == Head::Info)
			return Account_Info(socket, json);
	}
	return XQHttpHeadReply();
}

void XQHttpReplyAccount::buffer(QIODevice* socket, XQHttpHeadObject* head, const QByteArray& buffer)
{
	//qDebug() <<"接收到的数据"<< buffer;
	XQHttpReplyObject::buffer(socket,head, buffer);
}

void XQHttpReplyAccount::clientdisconnected(QIODevice* socket)
{
	QWriteLocker lock(&m_loginAccountLock);
	m_loginAccount.remove(socket);
}

void XQHttpReplyAccount::userMysql_init()
{
	auto mysql = m_userMysql;
	if (mysql == nullptr)return;
	/*qInfo() << "查询表是否存在,不存在将创建";*/
	QString tableName = UserTable;
	if (!mysql->tabelExists(tableName))
	{
		if (mysql->Query(XQAccountData().createTableSql(tableName)))
		{
			//PushServerLog << "<" + tableName + ">用户表创建成功";
		}
		else//发生错误
		{
			/*PushServerLog << "<" + tableName + ">用户表创建失败";
			emit error("<" + tableName + ">用户表创建失败");*/
		}
		//emit showMessage("<" + tableName + ">表创建成功", 10_s);
	}
}

HttpAccount::Verify* XQHttpReplyAccount::emailVerifyClass(const QString& email)
{
	auto& verify = m_emailVerify[email];
	if (verify==nullptr)
	{//不存在第一次创建
		verify = new Verify;
		new XQFuncEvent(this, [this] {if (!m_timer->isActive())m_timer->start(); });//激活定时器内存清理
	}
	return verify;
}

HttpAccount::Verify* XQHttpReplyAccount::accountVerifyClass(const QString& email)
{
	auto& verify = m_accountVerify[email];
	if (verify == nullptr)
	{//不存在第一次创建
		verify = new Verify;
		new XQFuncEvent(this, [this] {if (!m_timer->isActive())m_timer->start(); });//激活定时器内存清理	
	}
	return verify;
}

QString XQHttpReplyAccount::account_decode(const QJsonObject& json)
{
	if(json.contains("account"))
		return QByteArray::fromBase64(json["account"].toVariant().toByteArray());
	return QString();
}

QString XQHttpReplyAccount::password_decode(const QJsonObject& json)
{
	if (json.contains("password"))
		return QByteArray::fromBase64(json["password"].toVariant().toByteArray());
	return QString();
}

QString XQHttpReplyAccount::newPassword_decode(const QJsonObject& json)
{
	if (json.contains("newPassword"))
		return QByteArray::fromBase64(json["newPassword"].toVariant().toByteArray());
	return QString();
}

QStringList XQHttpReplyAccount::intersectFields(const QStringList& fields, const QSet<QString>& except)
{
	QSet<QString> set1;
	for (auto& item : fields)
		set1 << item;
	QSet<QString> set2;
	for (auto& item : XQAccountData::Fields())
		set2 << item;
	//去除不要的字段
	for (auto& item : except)
		set2.remove(item);
	//求交集
	set1.intersect(set2);
	QStringList list;
	for (auto& item : set1)
		list << std::move(item);
	return list;
}
//正则匹配
bool regexMatch(const QString& text,const QString& regex)
{
	//正则表达式先进行判断
	QRegularExpressionMatch match = QRegularExpression(regex).match(text);  // 进行匹配
	if (!match.hasMatch())
		return false;
	return true;
}
bool XQHttpReplyAccount::isEmailFormat(const QString& email)
{
	return regexMatch(email, R"([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})");// 邮箱地址的正则表达式
}

bool XQHttpReplyAccount::isAccountFormat(const QString& account)
{
	if (m_accountFormat.isEmpty())
		return true;
	return regexMatch(account,m_accountFormat);
}

bool XQHttpReplyAccount::isPasswordFormat(const QString& password)
{
	if (m_passwordFormat.isEmpty())
		return true;
	return regexMatch(password, m_passwordFormat);
}

bool XQHttpReplyAccount::emailFormatRecognition(const QString& email, HttpAccount::Result result, XQHttpHeadReply& reply)
{
	//判断邮箱格式
	if (!isEmailFormat(email))
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::EmailError));
		reply.setContent(variantMap_toJson({ {"email",email} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) email:%1 邮箱格式错误").arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
	return true;
}

bool XQHttpReplyAccount::accountFormatRecognition(const QString& account, HttpAccount::Result result, XQHttpHeadReply& reply)
{
	//判断邮箱格式
	if (account.isEmpty()||!isAccountFormat(account))
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::NewAccountFormatError));
		reply.setContent(variantMap_toJson({ {"account",account} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) account:%1 新账号格式错误").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
	return true;
}

bool XQHttpReplyAccount::passwordFormatRecognition(const QString& password, HttpAccount::Result result, XQHttpHeadReply& reply)
{
	//判断密码格式
	if (password.isEmpty()||!isPasswordFormat(password))
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::NewPasswordFormatError));
		reply.setContent(variantMap_toJson({ {"password",password} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) password:%1 密码格式错误").arg(password).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
	return true;
}

bool XQHttpReplyAccount::emailAccountRecognition(const QString& email, const QString& account, HttpAccount::Result result, XQHttpHeadReply& reply, QSharedPointer<XQMySql> mysql)
{
	if (mysql == nullptr)
		return false;
	auto data = accountInfo_mysql(account, "email", mysql);
	if (data.isNull())
		return false;//账号不存在
	if (data.toString()!=email)
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::EmailError));
		reply.setContent(variantMap_toJson({ {"email",email} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%3(%4) account:%1 email:%2 账号与邮箱不匹配").arg(account).arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));;
		return false;
	}
	return true;
}

bool XQHttpReplyAccount::verifyRecognition(QHash<QString, HttpAccount::Verify*>& hash, const QString& key, const QString& verify, const QString& email, HttpAccount::Result result, XQHttpHeadReply& reply)
{
	//查看此邮箱是否发起过验证码请求
	QReadLocker lock(&m_verifyLock);
	if (!hash.contains(key) || hash[key] == nullptr)
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::EmailError));
		reply.setContent(variantMap_toJson({ {"email",email},{"error","This mailbox did not receive a verification code request"} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) email:%1 此邮箱没有收到验证码请求").arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
	//查看是否超时了
	if (!hash[key]->isValid())
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::VerifyTimeout));
		reply.setContent(variantMap_toJson({ {"email",email},{"error","The verification code timed out"} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) email:%1 验证码超时了").arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
	//验证码是否匹配
	if (hash[key]->verify() != verify)
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::VerifyError));
		reply.setContent(variantMap_toJson({ {"email",email},{"error","The verification code timed out"} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) email:%1 验证码错误").arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return false;
	}
}

bool XQHttpReplyAccount::authentication(const QString& account, const QString& password, HttpAccount::Result result, XQHttpHeadReply& reply, QSharedPointer<XQMySql> mysql)
{
	if (mysql == nullptr)
		return false;
	//先找用户名是否存在
	if (!isAccountExist_mysql(account, mysql))
	{//没有这个账号
		reply.setHeader(Head::Error, error_toByteArray(Error::AccountNotExist));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) account:%1 没有这个账号").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));;
		return false;
	}
	if (password.isEmpty() || accountInfo_mysql(account, "password", mysql).toString() != password)
	{//密码错误
		reply.setHeader(Head::Error, error_toByteArray(Error::PasswordError));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) account:%1 密码错误").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));;
		return false;
	}
	return true;
}

bool XQHttpReplyAccount::sendMailVerify(const QString& email, HttpAccount::Verify* verify, HttpAccount::Result result, XQHttpHeadReply& reply)
{
	if (!verify->isFlush())
	{//时间还没到
		reply.setHeader(Head::Error, error_toByteArray(Error::VerifyTimeNotArrived));
		reply.setContent(variantMap_toJson({ {"verify",result_toByteArray(result)}, {"flush",verify->flushDateTime()},{"valid",verify->validDateTime()}}));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%5(%4) email:%1 time:%2 flush:%3 重新刷新时间未到")
			.arg(email)
			.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
			.arg(verify->flushDateTime().toString("yyyy-MM-dd hh:mm:ss"))
			.arg(result_toByteArray(result))
			.arg(result_toChinese(result));
		return false;
	}
	//获得新的验证码
	verify->newVerify();
	//发送的文本
	QString sendText = QString("验证码:%1 \r\n可刷新时间:%2(%3分)有效期至:%4(%5分)")
		.arg(verify->verify())
		.arg(verify->flushDateTime().toString("yyyy-MM-dd hh:mm:ss"))
		.arg(verify->flushInterval() / 1000 / 60)
		.arg(verify->validDateTime().toString("yyyy-MM-dd hh:mm:ss"))
		.arg(verify->validInterval() / 1000 / 60);
	//向指定邮箱发送验证码
	QEventLoop loop;
	bool flag;
	new XQFuncEvent(this, [&] {
		m_mail->setReceiver(email, email);
		flag = m_mail->SendMail(appName(), sendText);
		loop.quit();
		});
	loop.exec();
	if (!flag)
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::SendVerifyError));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%3(%2) email:%1 发送失败").arg(email).arg(result_toByteArray(result)).arg(result_toChinese(result));;
		return false;
	}
	//验证码发送成功，返回信息
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	reply.setContent(variantMap_toJson({ {"verify",result_toByteArray(result)},{"flush",verify->flushDateTime()},{"valid",verify->validDateTime()} }));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%4(%3) email:%1 %2 发送成功").arg(email).arg(sendText).arg(result_toByteArray(result)).arg(result_toChinese(result));;
	return false;
}

XQHttpHeadReply XQHttpReplyAccount::Account_Login(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountLogin;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	auto account = account_decode(json);
	auto password = password_decode(json);
	//数据库中查找
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	//身份认证
	if (!authentication(account, password, result,reply, mysql))
		return reply;
	//登录成功返回
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	//reply.setContent(acc.toJson());
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 登录成功").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	//保存登录状态
	QWriteLocker lock(&m_loginAccountLock);
	m_loginAccount[socket]=account;
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_Logout(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountLogout;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	auto account = loginAccount(socket);
	if (account.isEmpty())
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::NotLogin));
		return reply;
	}
	clientdisconnected(socket);//删除登录信息
	//登录成功返回
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_Register(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountRegister;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	auto map = json.toVariantMap();
	auto email = map["email"].toString();
	auto verify= map["verify"].toString();
	//判断邮箱格式
	if (!emailFormatRecognition(email, result, reply))
		return reply;
	//验证码识别
	if (!verifyRecognition(m_emailVerify, email, verify, email, result, reply))
		return reply;
	auto account = account_decode(json);
	auto password = password_decode(json);
	//检查下新账号的格式
	if (!accountFormatRecognition(account, result, reply))
		return reply;
	//检查下新密码的格式
	if (!passwordFormatRecognition(password, result, reply))
		return reply;
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	//检查账户是否存在同名的
	if (isAccountExist_mysql(account, mysql))
	{//账号已经存在了
		reply.setHeader(Head::Error, error_toByteArray(Error::AccountDuplicated));
		reply.setContent(variantMap_toJson({ {"account",account},{"error","Account number is repeated."} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) account:%1 账号重复了").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return reply;
	}
	//新建账号
	auto fields = intersectFields(map.keys());
	//删除不需要的数据
	for (auto& field : map.keys())
	{
		if (!fields.contains(field))
			map.remove(field);
	}
	XQAccountData acc(true,map);
	//修正账号和密码均为未加密的
	acc.account = account;
	acc.account = password;
	if(!acc.portrait_data.isNull())
		acc.portrait_data=acc.portrait_data.scaled(portraitMaxSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
	//插入数据
	if (!mysql->INSERT(UserTable,map.keys(),&acc))
	{
		if (isDebugModel(Http::Debug::error))
			XQLog(logName()) << QString("%2(%3) account:%1 创建账号失败").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result))<<mysql->error();
		return reply;
	}
	//清理验证码
	{
		QWriteLocker lock(&m_verifyLock);
		clearVerify(m_emailVerify, email);
	}

	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	//reply.setContent(accInfo.toJson(fields));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 创建账号完成").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_NewEmailVerify(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountNewEmailVerify;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	auto email = json["email"].toVariant().toByteArray();
	//判断邮箱格式
	if (!emailFormatRecognition(email, result,reply))
		return reply;
	if (emailBindAccountCount_mysql(email) >= emailBindAccountCount())
	{//绑定数量超出了
		reply.setHeader(Head::Error, error_toByteArray(Error::EmailBindOverboundCountError));
		reply.setContent(variantMap_toJson({ {"email",email},{"count",emailBindAccountCount()} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) email:%1 邮箱绑定数量超出限制了").arg(email).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return reply;
	}
	QWriteLocker lock(&m_verifyLock);
	auto verify = emailVerifyClass(email);
	sendMailVerify(email,verify, result,reply);
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_BindEmailVerify(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountBindEmailVerify;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	auto email = json["email"].toVariant().toByteArray();
	auto account = account_decode(json);
	//判断邮箱格式
	if (!emailFormatRecognition(email, result, reply))
		return reply;
	//数据库中查找
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	//判断当前邮箱是不是当前账号绑定
	if(!emailAccountRecognition(email,account, result,reply,mysql))
		return reply;
	QWriteLocker lock(&m_verifyLock);
	auto verify = accountVerifyClass(email);
	sendMailVerify(email, verify, result, reply);

	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_ModifyPassword(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountModifyPassword;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	//数据库
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto account = account_decode(json);
	auto password = password_decode(json);
	//身份认证
	if (!authentication(account, password, result, reply, mysql))
		return reply;
	auto newPassword = newPassword_decode(json);
	//检查下新密码的格式
	if (!passwordFormatRecognition(newPassword,result,reply))
		return reply;
	//检查下新密码与旧密码是否相同
	if (password==newPassword)
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::NewPasswordSameOld));
		reply.setContent(variantMap_toJson({ {"password",password} }));
		if (isDebugModel(Http::Debug::Run))
			XQLog(logName()) << QString("%2(%3) password:%1 新旧密码相同").arg(password).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return reply;
	}

	//更新密码数据
	if (!mysql->UPDATE(UserTable, { "password" }, { newPassword }, "`account`=?", { account }))
	{
		if (isDebugModel(Http::Debug::error))
			XQLog(logName()) << QString("%2(%3) account:%1 修改信息失败").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	}
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	//reply.setContent(accInfo.toJson(fields));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 更新密码完成").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_ModifyInfo(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountModifyInfo;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	//数据库
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto map=json.toVariantMap();
	auto account = loginAccount(socket);
	if(account.isEmpty())
	{
		account = account_decode(json);
		auto password = password_decode(json);
		//身份认证
		if (!authentication(account, password, result, reply, mysql))
			return reply;
	}
	auto fields = intersectFields(map.keys(), { "account","email","password"});//可以修改的字段
	//删除不需要的数据
	for (auto&field:map.keys())
	{
		if (!fields.contains(field))
			map.remove(field);
	}
	XQAccountData acc(true, map);
	if (!acc.portrait_data.isNull())
		acc.portrait_data = acc.portrait_data.scaled(portraitMaxSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
	//更新数据
	if (!mysql->UPDATE(UserTable, map.keys(),&acc, "`account`=?", {account}))
	{
		if (isDebugModel(Http::Debug::error))
			XQLog(logName()) << QString("%2(%3) account:%1 修改信息失败").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	}
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	//reply.setContent(accInfo.toJson(fields));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 更新数据完成").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_ModifyEmail(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountModifyEmail;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	//数据库
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto account = this->loginAccount(socket);//账号
	if (account.isEmpty())//没有登录
	{
		account = account_decode(json);
		auto password = password_decode(json);

		//身份认证
		if (!authentication(account, password, result, reply, mysql))
			return reply;
	}
	
	auto email = json["email"].toString();
	auto newEmail = json["newEmail"].toString();
	auto verify = json["verify"].toString();
	auto newVerify = json["newVerify"].toString();
	//验证码识别 (旧邮箱验证码识别)
	if (!verifyRecognition(m_accountVerify, account, verify, email, result, reply))
		return reply;
	//验证码识别  (新邮箱验证码识别)
	if (!verifyRecognition(m_emailVerify, newEmail, newVerify, newEmail, result, reply))
		return reply;
	//开始更新邮箱
	if (!mysql->UPDATE(UserTable, {"email"}, {newEmail}, "`account`=?", {account}))
	{
		reply.setHeader(Head::Error, error_toByteArray(Error::ServerError));
		reply.setContent(variantMap_toJson({ {"email",email},{"error","Failed to modify the mailbox"} }));
		if (isDebugModel(Http::Debug::error))
			XQLog(logName()) << QString("%2(%3) account:%1 修改邮箱失败").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
		return reply;
	}
	{
		QWriteLocker lock(&m_verifyLock);
		//清理验证码
		clearVerify(m_accountVerify, account);
		clearVerify(m_emailVerify, newEmail);
	}

	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	//reply.setContent(accInfo.toJson(fields));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 更新邮箱完成").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_portrait(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountPortrait;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());
	//数据库中查找
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto account = this->loginAccount(socket);//账号
	if (account.isEmpty())
	{
		account = account_decode(json);
		if (!isAccountExist_mysql(account, mysql))
		{
			reply.setHeader(Head::Error, error_toByteArray(Error::AccountNotExist));
			reply.setContent(variantMap_toJson({ {"account",account} }));
			if (isDebugModel(Http::Debug::Run))
				XQLog(logName()) << QString("%2(%3) account:%1 账号不存在").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
			return reply;
		}
	}
	//开始查询头像并准备返回数据
	auto data = accountInfo_mysql(account, { "portrait_data","portrait_format"}, mysql);
	//成功返回用户信息
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	reply.setContent(data.toJson({ "portrait_data","portrait_format" }));
	return reply;
}

XQHttpHeadReply XQHttpReplyAccount::Account_Info(QIODevice* socket, const QJsonObject& json)
{
	auto result = Result::AccountInfo;
	XQHttpHeadReply reply;
	reply.setHeader(Head::App, appName());

	//数据库中查找
	auto mysql = m_userMysql->cloneDatabase_SharedPointer();
	auto account = this->loginAccount(socket);//账号
	if(account.isEmpty())//没有登录
	{
		account = account_decode(json);
		auto password = password_decode(json);
		
		//身份认证
		if (!authentication(account, password, result, reply, mysql))
			return reply;
	}
	//查询指定字段信息
	auto fields = json["fields"].toVariant().toStringList();
	auto accInfo = accountInfo_mysql(account,fields,mysql);
	//成功返回用户信息
	reply.setHeader(Head::Error, error_toByteArray(Error::NoError));
	reply.setHeader(Head::Result, result_toByteArray(result));
	reply.setContent(accInfo.toJson(fields));
	if (isDebugModel(Http::Debug::Run))
		XQLog(logName()) << QString("%2(%3) account:%1 返回信息").arg(account).arg(result_toChinese(result)).arg(result_toByteArray(result));
	return reply;
}
